//==============================================================================
//
//       DLRnd - the (long) pseudo random generator in the ofc-library
//
//               Copyright (C) 2003  Dick van Oudheusden
//  
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free
// Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
//==============================================================================
// 
//  $Date: 2008-08-02 05:58:14 $ $Revision: 1.6 $
//
//==============================================================================

#include "ofc/DLRnd.h"

#include "ofc/warning.h"


#if _INTERFACE_

#include <stdint.h>

#include "ofc/config.h"

#include "ofc/DRandomable.h"

//
// The DLRnd class implements a pseudo random generator bases on a 
// generalized feedback shift register random generator. It is not as 
// fast as the generator used in the @class(DRnd) but this one passes the 
// Marsaglia's 'Diehard' statistical tests and it has a long period 
// of 2^800. This class is 'inspired' by the code present on the site
// @link(http://remus.rutgers.edu/~rhoads)
//
// @example
// #include <stdio.h>
// #include "ofc/DLRnd.h"
// 
// int main(int argc, char *argv[])
// {
//   DLRnd *rnd1 = [DLRnd alloc];
//   DLRnd *rnd2 = [DLRnd new  ];
// 
//   [rnd1 init :12345678];               // Init with a seed value
// 
//                                        // Get pseudo random values
//   printf("Pseudo random long value:%ld.\n", [rnd1 nextLong]);
//   printf("Pseudo random int value with range [1,100]:%d.\n", [rnd1 nextInt :1 :100]);
// 
//   [rnd2 seed :87654321];              // Set a seed value
// 
//                                       // Get pseudo random values
//   printf("Pseudo random double value:%f.\n", [rnd2 nextDouble]);
//   printf("Pseudo random double value with range [0.1,0.3]:%f.\n", [rnd2 nextDouble :0.1 :0.3]);
// 
//   [rnd1 free];                        // Cleanup
//   [rnd2 free];
// 
//   return 0;
// }
// 

@interface DLRnd : DObject <DRandomable>
{
@private
  uint32_t _seeds[25];  // the seeds for the generator
  int      _index;      // the index in the seeds
}

#endif


#define LRND_MAX   (4294967296.0)
#define LRND_SEEDS (25)



@implementation DLRnd


const static uint32_t magic[] = { 0x0, 0x8ebfd028 };


//// Constructors

//
// Initialise a non-seeded random generator
//
// @return the object
//

- (DLRnd *) init
{
  [super init];

  _index = 0;
   
  [self seed :1];
  
  return self;
}

//
// Initialise a seeded random generator
//
// @param seed     the seed to be used
// 
// @return the object
//

- (DLRnd *) init :(unsigned long) seed
{
  [super init];
  
  _index = 0;

  [self seed :seed];
  
  return self;
}


//// Member methods

//
// Set the seed for the random generator
// 
// @param seed     the seed for the random generator
//
// @return the object
//

- (DLRnd *) seed :(unsigned long) seed
{
  int s;
  
  seed |= 1;
  
  _seeds[0] = (uint32_t) (seed & 0xffffffff);
  for (s = 1; s < LRND_SEEDS; s++)
  {
    _seeds[s] = (69069 * _seeds[s-1]) & 0xffffffff;
  }  
  
  return self;
}


//// Random generator methods

static uint32_t nextValue(DLRnd *self)
{
  uint32_t value;
  int      s;
  
  if (self->_index >= LRND_SEEDS)
  {
    s = 0;
    while (s < LRND_SEEDS - 7)
    {
      self->_seeds[s] = self->_seeds[s + 7] ^ (self->_seeds[s] >> 1) ^ magic[self->_seeds[s] & 1];
      s++;
    }
    while (s < LRND_SEEDS)
    {
      self->_seeds[s] = self->_seeds[s + (7 - LRND_SEEDS)] ^ (self->_seeds[s] >> 1) ^ magic[self->_seeds[s] & 1];
      s++;
    }
    self->_index = 0;
  }
  
  value = self->_seeds[self->_index];
  value ^= (value <<  7) & 0x2b5b2500;
  value ^= (value << 15) & 0xdb8b0000;
  value &= 0xffffffff;
  value ^= (value >> 16);
  
  // printf("Value= %lu\n", value);
  (self->_index)++;
  
  return value;
}

//
// Get the next long from the generator
//  
// @return the next long
//

- (long) nextLong 
{
  return (long)((int32_t)(nextValue(self)));
}

//
// Get the next ranged long from the generator
// 
// @param from     the start of the range
// @param to       the end of the range
// 
// @return the next long
// 

- (long) nextLong :(long) from :(long) to
{
  return from + (to - from + 1) * ((double) nextValue(self) / LRND_MAX);
}

//
// Get the next integer from the generator
//  
// @return the next integer
//

- (int) nextInt
{
  return (int)(nextValue(self));
}

//
// Get the next ranged integer from the generator
// 
// @param from     the start of the range
// @param to       the end of the range
// 
// @return the next integer
// 

- (int) nextInt :(int) from :(int) to
{
  return from + (to - from + 1) * ((double) nextValue(self) / LRND_MAX);
}

//
// Get the next double from the generator (0 <= d < 1)
//  
// @return the next double
//

- (double) nextDouble
{
  return (double) nextValue(self) / LRND_MAX;
}

//
// Get the next double from the generator (from <= dE < to)
// 
// @param from     the start of the range
// @param to       the end of the range
// 
// @return the next double
// 

- (double) nextDouble :(double) from :(double) to
{
  return from + (to - from) * ((double) nextValue(self) / LRND_MAX);
}


@end

/*==========================================================================*/
